import { _decorator, Component, Node, ImageAsset, instantiate, resources, Sprite, SpriteFrame, Prefab, EventTouch } from 'cc';
import { AbilityStone } from '../Entity/AbilityStone';
import { BloodBottleEntity } from '../Entity/BloodBottleEntity';
import { Entity } from '../Entity/def/Entity';
import { Fight } from '../Entity/def/Fight';
import { DoorEntity } from '../Entity/DoorEntity';
import { KeyEntity } from '../Entity/KeyEntity';
import { MonsterEntity } from '../Entity/MonsterEntity';
import { AngelNPC } from '../Entity/NPC/AngelNPC';
import { StairwayEntity } from '../Entity/StairwayEntity';
import { StoreEntity } from '../Entity/StoreEntity';
import { WallEntity } from '../Entity/WallEntity';
import { Global } from '../Global';
import { Pathfinder } from '../Utils/Pathfinder';
import { EntityConfig, MapConfig } from './MapConfig';
const { ccclass, property } = _decorator;

@ccclass('EntityManager')
export class EntityManager extends Component {

    @property(Prefab)
    entity: Prefab = null

    @property(Prefab)
    storeEntity: Prefab = null

    mapConfig: MapConfig = null

    currentFloor: Map<Number, Map<String, Entity>> = new Map()

    start() {
        Global.em = this
        this.mapConfig = new MapConfig()
    }

    update(deltaTime: number) {

    }

    loadEntity(floor: number) {
        console.log('load entities')
        this.node.removeAllChildren()
        // 检查缓存
        const nodes = this.currentFloor.get(floor)
        if (nodes !== undefined) {
            // 防止多方块结构重复加载
            const added = new Set()
            nodes.forEach(entity => {
                if (added.has(entity.node.uuid)) {
                    return
                }
                this.node.addChild(entity.node)
                added.add(entity.node.uuid)
            })
            added.clear()
            return
        }
        // 从配置加载
        const entities = this.mapConfig.loadEntities(floor)
        entities.forEach((es) => {
            if (es.type === 'store') {
                this.buildMultiEntity(es, floor)
                return
            }
            es.indexs.forEach(is => {
                if (!is || is === '') {
                    return
                }
                const indexsArray = is.split('-')
                const x: number = Number.parseInt(indexsArray[0])
                const y: number = Number.parseInt(indexsArray[1])
                this.buildAddEntityChild(es, x, y, floor)
            })
        })
    }

    buildMultiEntity(es: EntityConfig, floor: number) {
        if (es.type === 'store') {
            const storeNode = instantiate(this.storeEntity)
            const anchor = this.parseIndex(es.indexs[0])
            storeNode.setPosition(28 * anchor.x, 28 * anchor.y)
            this.node.addChild(storeNode)

            const store = new StoreEntity([anchor.x, anchor.y], es.type)
            store.node = storeNode
            es.indexs.forEach(is => {
                if (!is || is === '') {
                    return
                }
                const index = this.parseIndex(is)
                if (!this.currentFloor.get(floor)) {
                    this.currentFloor.set(floor, new Map())
                }
                this.currentFloor.get(floor).set(index.x + '-' + index.y, store)
            })
        }
    }

    private parseIndex(index: string) {
        if (!index || index === '') {
            return
        }
        const indexsArray = index.split('-')
        return {
            x: Number.parseInt(indexsArray[0]),
            y: Number.parseInt(indexsArray[1])
        }
    }

    loadHero(floor: number, heroState?: string) {
        console.log('load hero')
        const indexs = this.mapConfig.loadHero(floor, heroState)
        const indexsArray = indexs.split('-')
        const x: number = Number.parseInt(indexsArray[0])
        const y: number = Number.parseInt(indexsArray[1])
        console.log('hero index:', x, y)
        return [x, y]
    }

    private buildAddEntityChild(config: EntityConfig, x: number, y: number, floor: number) {
        resources.load(config.resource, ImageAsset, (err, imageAsset) => {
            if (err) {
                return console.error("ImageAssert load failed, err:" + err.message);
            }

            const type = config.type.split('-')
            let entity: Entity = this.buildEnity(type, x, y, config.fight);
            if (!entity) {
                return
            }

            const node = instantiate(this.entity);
            node.setPosition(14 + 28 * x, 14 + 28 * y)
            const sp = node.getComponent(Sprite)
            sp.spriteFrame = SpriteFrame.createWithImage(imageAsset);
            entity.node = node

            this.setCache(floor, entity)
            this.node.addChild(node)
        });
    }

    private buildEnity(type: string[], x: number, y: number, fight?: Fight): Entity {
        switch (type[0]) {
            case 'walls': {
                return new WallEntity([x, y], type[1])
            }
            case 'doors': {
                return new DoorEntity([x, y], type[1])
            }
            case 'stairway': {
                return new StairwayEntity([x, y], type[1])
            }
            case 'keys': {
                return new KeyEntity([x, y], type[1])
            }
            case 'abilityStone': {
                return new AbilityStone([x, y], type[1])
            }
            case 'bloodBottle': {
                return new BloodBottleEntity([x, y], type[1])
            }
            case 'monster': {
                return new MonsterEntity([x, y], type[1], fight)
            }
            case 'npc': {
                switch (type[1]) {
                    case 'angel': {
                        return new AngelNPC([x, y], type[1])
                    }
                }
            }
        }
        return null
    }

    private setCache(floor: number, entity: Entity) {
        if (!this.currentFloor.get(floor)) {
            this.currentFloor.set(floor, new Map())
        }
        this.currentFloor.get(floor).set(entity.index[0] + '-' + entity.index[1], entity)
    }

    removeEntity(floor: number, entity: Entity) {
        const entities = this.currentFloor.get(floor)
        if (entities === null || entities === undefined) {
            return
        }
        entities.delete(entity.index[0] + '-' + entity.index[1])
        this.node.removeChild(entity.node)
    }

    static _quickMoveLock = false;


    onClick(event: EventTouch) {
        if (Global.key.globalMoveKey) {
            return
        }
        if (EntityManager._quickMoveLock) {
            Global.heroManage.cancelQuaickMove()
        }

        const touch = event.touch.getUILocation();
        const cur = this.node.getWorldPosition();
        const x = Math.floor((touch.x - cur.x) / 28)
        const y = Math.floor((touch.y - cur.y) / 28)
        const start = Global.heroManage.getPos()
        if (start.x === x && start.y === y) {
            return
        }

        EntityManager._quickMoveLock = true
        const path = Pathfinder.findPath([start.x, start.y], [x, y], this.currentFloor.get(start.floor), true)
        if (!path) {
            Global.popUtil.popUp('此路不通')
            EntityManager._quickMoveLock = false
            return
        }

        if (!this.checkTarget(x + '-' + y, start.floor)) {
            EntityManager._quickMoveLock = false
            return
        }

        Global.heroManage.moveByPath(path, this.removeClickLock)
    }

    removeClickLock() {
        EntityManager._quickMoveLock = false
    }

    private checkTarget(index: string, floor: number): boolean {
        const entity = this.currentFloor.get(floor).get(index)
        if (!entity) {
            return true
        }
        return entity.preCheck()
    }

}

